package com.boesch.electroOffice.presentation.staff;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.event.ActionEvent;
import javax.faces.event.ComponentSystemEvent;

import org.joda.time.LocalDate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

import com.boesch.electroOffice.business.businessObject.IdentifierBusinessObject;
import com.boesch.electroOffice.business.businessObject.StaffBusinessObject;
import com.boesch.electroOffice.business.common.BusinessException;
import com.boesch.electroOffice.dataaccess.common.IllegalDataAccessException;
import com.boesch.electroOffice.model.electroOffice.Identifier;
import com.boesch.electroOffice.model.enums.SessionParameter;
import com.boesch.electroOffice.model.enums.UIMessages;
import com.boesch.electroOffice.model.wrapper.WeekReportEntry;
import com.boesch.electroOffice.utils.DateUtils;
import com.boesch.electroOffice.utils.MessageUtils;
import com.boesch.electroOffice.utils.PortletUtils;
import com.boesch.electroOffice.utils.UserUtils;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.model.User;

@Controller
@ManagedBean
@SessionScoped
public class WeekReportController implements Serializable {

	private static final long serialVersionUID = 819513844309818606L;
	private static final Log log = LogFactoryUtil.getLog(WeekReportController.class);

	@Autowired
	private StaffBusinessObject staffBusinessObject;
	@Autowired
	private IdentifierBusinessObject identifierBusinessObject;

	private LocalDate weekReportDateMonday;
	private Date chosenDate;

	private Identifier depotManagement;
	private Identifier appointmentHours;
	private Identifier holiday;
	private Identifier sickness;
	private Identifier military;
	private Identifier occupational;
	private Identifier nonoccupational;
	private Identifier compensation;

	private WeekReportEntry depotManagementEntry = new WeekReportEntry();
	private WeekReportEntry holidayEntry = new WeekReportEntry();
	private WeekReportEntry compensationEntry = new WeekReportEntry();
	private WeekReportEntry sicknessEntry = new WeekReportEntry();
	private WeekReportEntry militaryEntry = new WeekReportEntry();
	private WeekReportEntry occupationalEntry = new WeekReportEntry();
	private WeekReportEntry nonoccupationalEntry = new WeekReportEntry();

	private List<WeekReportEntry> prodWeekReportEntries = new ArrayList<WeekReportEntry>();
	private List<WeekReportEntry> unprodWeekReportEntries = new ArrayList<WeekReportEntry>();

	private double totalProdMonday;
	private double totalProdTuesday;
	private double totalProdWednesday;
	private double totalProdThursday;
	private double totalProdFriday;
	private double totalProdSaturday;
	private double totalProdSunday;
	private double totalProdTotal;

	private double totalUnprodMonday;
	private double totalUnprodTuesday;
	private double totalUnprodWednesday;
	private double totalUnprodThursday;
	private double totalUnprodFriday;
	private double totalUnprodSaturday;
	private double totalUnprodSunday;
	private double totalUnprodTotal;

	public void loadData(ComponentSystemEvent event) {
		try {
			clearTotalProdHours();
			clearTotalUnprodHours();
			loadIdentifiers();
			if (null == weekReportDateMonday || "true".equals(PortletUtils.getSessionAttribute(SessionParameter.RESET.getValue()))) {
				this.weekReportDateMonday = DateUtils.getDateOfMondayInCurrentWeek();
				PortletUtils.setSessionAttribute(SessionParameter.RESET.getValue(), "false");
			}
			User currentUser = UserUtils.getCurrentUser();
			long userId = currentUser.getUserId();
			int year = DateUtils.getYearByLocalDate(weekReportDateMonday);
			int week = DateUtils.getWeekByLocalDate(weekReportDateMonday);
			this.prodWeekReportEntries = staffBusinessObject.getWeekReportEntriesByUserIdCalendarWeekAndIdentifier(userId, year, week, appointmentHours);
			this.depotManagementEntry = staffBusinessObject.getWeekReportEntryByCalendarWeekAndIdentifier(userId, year, week, depotManagement);
			this.holidayEntry = staffBusinessObject.getWeekReportEntryByCalendarWeekAndIdentifier(userId, year, week, holiday);
			this.compensationEntry = staffBusinessObject.getWeekReportEntryByCalendarWeekAndIdentifier(userId, year, week, compensation);
			this.sicknessEntry = staffBusinessObject.getWeekReportEntryByCalendarWeekAndIdentifier(userId, year, week, sickness);
			this.militaryEntry = staffBusinessObject.getWeekReportEntryByCalendarWeekAndIdentifier(userId, year, week, military);
			this.occupationalEntry = staffBusinessObject.getWeekReportEntryByCalendarWeekAndIdentifier(userId, year, week, occupational);
			this.nonoccupationalEntry = staffBusinessObject.getWeekReportEntryByCalendarWeekAndIdentifier(userId, year, week, nonoccupational);
			createUnprodEntryList();
			calculateTotalProdHours();
			calculateTotalUnprodHours();
		} catch (IllegalDataAccessException e) {
			MessageUtils.addErrorMessage("Daten für den Wochenrapport konnten nicht geladen werden.");
			log.error("Failed to load data for week report", e);
		} catch (BusinessException e) {
			MessageUtils.addErrorMessage("Daten für den Wochenrapport konnten nicht geladen werden.");
			log.error("Failed to load data for week report", e);
		}
	}

	private void loadIdentifiers() {
		try {
			depotManagement = identifierBusinessObject.getIdentifierByEntityAndIdentifier("WORKING-IDENTIFIER", "DEPOT-MANAGEMENT");
			appointmentHours = identifierBusinessObject.getIdentifierByEntityAndIdentifier("WORKING-IDENTIFIER", "APPOINTMENT");
			holiday = identifierBusinessObject.getIdentifierByEntityAndIdentifier("WORKING-IDENTIFIER", "HOLIDAY");
			sickness = identifierBusinessObject.getIdentifierByEntityAndIdentifier("WORKING-IDENTIFIER", "SICKNESS");
			military = identifierBusinessObject.getIdentifierByEntityAndIdentifier("WORKING-IDENTIFIER", "MILITARY");
			occupational = identifierBusinessObject.getIdentifierByEntityAndIdentifier("WORKING-IDENTIFIER", "OCCUPATIONAL-ACCIDENT");
			nonoccupational = identifierBusinessObject.getIdentifierByEntityAndIdentifier("WORKING-IDENTIFIER", "NON-OCCUPATIONAL-ACCIDENT");
			compensation = identifierBusinessObject.getIdentifierByEntityAndIdentifier("WORKING-IDENTIFIER", "COMPENSATION");
		} catch (BusinessException e) {
			log.error("Failed to load working identifiers!", e);
		} catch (IllegalDataAccessException e) {
			log.error("Failed to load working identifiers!", e);
		}
	}

	public void navigateWeekForward(ActionEvent event) {
		this.weekReportDateMonday = DateUtils.getDatePlusDays(weekReportDateMonday, 7);
	}

	public void navigateWeekBackward(ActionEvent event) {
		this.weekReportDateMonday = DateUtils.getDateMinusDays(weekReportDateMonday, 7);
	}

	public void saveWeekReport(ActionEvent event) {
		User currentUser = UserUtils.getCurrentUser();
		for (WeekReportEntry entry : unprodWeekReportEntries) {
			if (reportEntryHasHoursFilled(entry)) {
				try {
					staffBusinessObject.saveWeekReportEntry(entry, currentUser);
					MessageUtils.addInfoMessage(UIMessages.SAVE_WEEK_REPORT_OK.getMessage());
				} catch (IllegalDataAccessException e) {
					log.error("Failed to save weekReportEntry!", e);
					MessageUtils.addErrorMessage(UIMessages.SAVE_WEEK_REPORT_ERROR.getMessage());
				} catch (BusinessException e) {
					log.error("Failed to save weekReportEntry!", e);
					MessageUtils.addErrorMessage(UIMessages.SAVE_WEEK_REPORT_ERROR.getMessage());
				}
			}
		}
	}

	public void closeWeekReport(ActionEvent event) {

	}

	public void showWeekReport() {
		if (null != chosenDate) {
			LocalDate date = DateUtils.convertDateToLocalDate(chosenDate);
			this.weekReportDateMonday = DateUtils.getDateOfMondayByLocalDate(date);
		}
	}

	public int getCalendarWeek() {
		return DateUtils.getWeekByLocalDate(weekReportDateMonday);
	}

	public String getWeekReportDateMondayString() {
		return DateUtils.convertLocalDateToString(weekReportDateMonday);
	}

	public String getWeekReportDateSundayString() {
		LocalDate sunday = DateUtils.getDatePlusDays(weekReportDateMonday, 6);
		return DateUtils.convertLocalDateToString(sunday);
	}

	public List<WeekReportEntry> getProdWeekReportEntries() {
		return prodWeekReportEntries;
	}

	public List<WeekReportEntry> getUnprodWeekReportEntries() {
		return unprodWeekReportEntries;
	}

	public double getTotalProdMonday() {
		return totalProdMonday;
	}

	public double getTotalProdTuesday() {
		return totalProdTuesday;
	}

	public double getTotalProdWednesday() {
		return totalProdWednesday;
	}

	public double getTotalProdThursday() {
		return totalProdThursday;
	}

	public double getTotalProdFriday() {
		return totalProdFriday;
	}

	public double getTotalProdSaturday() {
		return totalProdSaturday;
	}

	public double getTotalProdSunday() {
		return totalProdSunday;
	}

	public double getTotalProdTotal() {
		return totalProdTotal;
	}

	public double getTotalUnprodMonday() {
		return totalUnprodMonday;
	}

	public double getTotalUnprodTuesday() {
		return totalUnprodTuesday;
	}

	public double getTotalUnprodWednesday() {
		return totalUnprodWednesday;
	}

	public double getTotalUnprodThursday() {
		return totalUnprodThursday;
	}

	public double getTotalUnprodFriday() {
		return totalUnprodFriday;
	}

	public double getTotalUnprodSaturday() {
		return totalUnprodSaturday;
	}

	public double getTotalUnprodSunday() {
		return totalUnprodSunday;
	}

	public double getTotalUnprodTotal() {
		return totalUnprodTotal;
	}

	public double getTotalMonday() {
		return totalProdMonday + totalUnprodMonday;
	}

	public double getTotalTuesday() {
		return totalProdTuesday + totalUnprodTuesday;
	}

	public double getTotalWednesday() {
		return totalProdWednesday + totalUnprodWednesday;
	}

	public double getTotalThursday() {
		return totalProdThursday + totalUnprodThursday;
	}

	public double getTotalFriday() {
		return totalProdFriday + totalUnprodFriday;
	}

	public double getTotalSaturday() {
		return totalProdSaturday + totalUnprodSaturday;
	}

	public double getTotalSunday() {
		return totalProdSunday + totalUnprodSunday;
	}

	public double getTotalTotal() {
		return totalProdTotal + totalUnprodTotal;
	}

	public double getCompensationMonday() {
		return getTotalMonday() - 8;
	}

	public double getCompensationTuesday() {
		return getTotalTuesday() - 8;
	}

	public double getCompensationWednesday() {
		return getTotalWednesday() - 8;
	}

	public double getCompensationThursday() {
		return getTotalThursday() - 8;
	}

	public double getCompensationFriday() {
		return getTotalFriday() - 8;
	}

	public double getCompensationSaturday() {
		return getTotalSaturday();
	}

	public double getCompensationSunday() {
		return getTotalMonday();
	}

	public double getCompensationTotal() {
		return getTotalTotal() - 40;
	}

	public Date getChosenDate() {
		return chosenDate;
	}

	public void setChosenDate(Date chosenDate) {
		this.chosenDate = chosenDate;
	}

	private void calculateTotalProdHours() {
		for (WeekReportEntry entry : prodWeekReportEntries) {
			this.totalProdMonday = totalProdMonday + (null != entry.getMonday() ? entry.getMonday().getHours() : 0.0);
			this.totalProdTuesday = totalProdTuesday + (null != entry.getTuesday() ? entry.getTuesday().getHours() : 0.0);
			this.totalProdWednesday = totalProdWednesday + (null != entry.getWednesday() ? entry.getWednesday().getHours() : 0.0);
			this.totalProdThursday = totalProdThursday + (null != entry.getThursday() ? entry.getThursday().getHours() : 0.0);
			this.totalProdFriday = totalProdFriday + (null != entry.getFriday() ? entry.getFriday().getHours() : 0.0);
			this.totalProdSaturday = totalProdSaturday + (null != entry.getSaturday() ? entry.getSaturday().getHours() : 0.0);
			this.totalProdSunday = totalProdSunday + (null != entry.getSunday() ? entry.getSunday().getHours() : 0.0);
		}
		this.totalProdTotal = totalProdMonday + totalProdTuesday + totalProdWednesday + totalProdThursday + totalProdFriday + totalProdSaturday + totalProdSunday;
	}

	private void calculateTotalUnprodHours() {
		addDepotManagementHours();
		addHolidayHours();
		addCompensationHours();
		addSicknessHours();
		addMilitaryHours();
		addOccupationalHours();
		addNonoccupationalHours();
	}

	private void addDepotManagementHours() {
		this.totalUnprodMonday = totalUnprodMonday + (null != depotManagementEntry.getMonday() ? depotManagementEntry.getMonday().getHours() : 0.0);
		this.totalUnprodTuesday = totalUnprodTuesday + (null != depotManagementEntry.getTuesday() ? depotManagementEntry.getTuesday().getHours() : 0.0);
		this.totalUnprodWednesday = totalUnprodWednesday + (null != depotManagementEntry.getWednesday() ? depotManagementEntry.getWednesday().getHours() : 0.0);
		this.totalUnprodThursday = totalUnprodThursday + (null != depotManagementEntry.getThursday() ? depotManagementEntry.getThursday().getHours() : 0.0);
		this.totalUnprodFriday = totalUnprodFriday + (null != depotManagementEntry.getFriday() ? depotManagementEntry.getFriday().getHours() : 0.0);
		this.totalUnprodSaturday = totalUnprodSaturday + (null != depotManagementEntry.getSaturday() ? depotManagementEntry.getSaturday().getHours() : 0.0);
		this.totalUnprodSunday = totalUnprodSunday + (null != depotManagementEntry.getSunday() ? depotManagementEntry.getSunday().getHours() : 0.0);
	}

	private void addHolidayHours() {
		this.totalUnprodMonday = totalUnprodMonday + (null != holidayEntry.getMonday() ? holidayEntry.getMonday().getHours() : 0.0);
		this.totalUnprodTuesday = totalUnprodTuesday + (null != holidayEntry.getTuesday() ? holidayEntry.getTuesday().getHours() : 0.0);
		this.totalUnprodWednesday = totalUnprodWednesday + (null != holidayEntry.getWednesday() ? holidayEntry.getWednesday().getHours() : 0.0);
		this.totalUnprodThursday = totalUnprodThursday + (null != holidayEntry.getThursday() ? holidayEntry.getThursday().getHours() : 0.0);
		this.totalUnprodFriday = totalUnprodFriday + (null != holidayEntry.getFriday() ? holidayEntry.getFriday().getHours() : 0.0);
		this.totalUnprodSaturday = totalUnprodSaturday + (null != holidayEntry.getSaturday() ? holidayEntry.getSaturday().getHours() : 0.0);
		this.totalUnprodSunday = totalUnprodSunday + (null != holidayEntry.getSunday() ? holidayEntry.getSunday().getHours() : 0.0);
	}

	private void addCompensationHours() {
		this.totalUnprodMonday = totalUnprodMonday + (null != compensationEntry.getMonday() ? compensationEntry.getMonday().getHours() : 0.0);
		this.totalUnprodTuesday = totalUnprodTuesday + (null != compensationEntry.getTuesday() ? compensationEntry.getTuesday().getHours() : 0.0);
		this.totalUnprodWednesday = totalUnprodWednesday + (null != compensationEntry.getWednesday() ? compensationEntry.getWednesday().getHours() : 0.0);
		this.totalUnprodThursday = totalUnprodThursday + (null != compensationEntry.getThursday() ? compensationEntry.getThursday().getHours() : 0.0);
		this.totalUnprodFriday = totalUnprodFriday + (null != compensationEntry.getFriday() ? compensationEntry.getFriday().getHours() : 0.0);
		this.totalUnprodSaturday = totalUnprodSaturday + (null != compensationEntry.getSaturday() ? compensationEntry.getSaturday().getHours() : 0.0);
		this.totalUnprodSunday = totalUnprodSunday + (null != compensationEntry.getSunday() ? compensationEntry.getSunday().getHours() : 0.0);
	}

	private void addSicknessHours() {
		this.totalUnprodMonday = totalUnprodMonday + (null != sicknessEntry.getMonday() ? sicknessEntry.getMonday().getHours() : 0.0);
		this.totalUnprodTuesday = totalUnprodTuesday + (null != sicknessEntry.getTuesday() ? sicknessEntry.getTuesday().getHours() : 0.0);
		this.totalUnprodWednesday = totalUnprodWednesday + (null != sicknessEntry.getWednesday() ? sicknessEntry.getWednesday().getHours() : 0.0);
		this.totalUnprodThursday = totalUnprodThursday + (null != sicknessEntry.getThursday() ? sicknessEntry.getThursday().getHours() : 0.0);
		this.totalUnprodFriday = totalUnprodFriday + (null != sicknessEntry.getFriday() ? sicknessEntry.getFriday().getHours() : 0.0);
		this.totalUnprodSaturday = totalUnprodSaturday + (null != sicknessEntry.getSaturday() ? sicknessEntry.getSaturday().getHours() : 0.0);
		this.totalUnprodSunday = totalUnprodSunday + (null != sicknessEntry.getSunday() ? sicknessEntry.getSunday().getHours() : 0.0);
	}

	private void addMilitaryHours() {
		this.totalUnprodMonday = totalUnprodMonday + (null != militaryEntry.getMonday() ? militaryEntry.getMonday().getHours() : 0.0);
		this.totalUnprodTuesday = totalUnprodTuesday + (null != militaryEntry.getTuesday() ? militaryEntry.getTuesday().getHours() : 0.0);
		this.totalUnprodWednesday = totalUnprodWednesday + (null != militaryEntry.getWednesday() ? militaryEntry.getWednesday().getHours() : 0.0);
		this.totalUnprodThursday = totalUnprodThursday + (null != militaryEntry.getThursday() ? militaryEntry.getThursday().getHours() : 0.0);
		this.totalUnprodFriday = totalUnprodFriday + (null != militaryEntry.getFriday() ? militaryEntry.getFriday().getHours() : 0.0);
		this.totalUnprodSaturday = totalUnprodSaturday + (null != militaryEntry.getSaturday() ? militaryEntry.getSaturday().getHours() : 0.0);
		this.totalUnprodSunday = totalUnprodSunday + (null != militaryEntry.getSunday() ? militaryEntry.getSunday().getHours() : 0.0);
	}

	private void addOccupationalHours() {
		this.totalUnprodMonday = totalUnprodMonday + (null != occupationalEntry.getMonday() ? occupationalEntry.getMonday().getHours() : 0.0);
		this.totalUnprodTuesday = totalUnprodTuesday + (null != occupationalEntry.getTuesday() ? occupationalEntry.getTuesday().getHours() : 0.0);
		this.totalUnprodWednesday = totalUnprodWednesday + (null != occupationalEntry.getWednesday() ? occupationalEntry.getWednesday().getHours() : 0.0);
		this.totalUnprodThursday = totalUnprodThursday + (null != occupationalEntry.getThursday() ? occupationalEntry.getThursday().getHours() : 0.0);
		this.totalUnprodFriday = totalUnprodFriday + (null != occupationalEntry.getFriday() ? occupationalEntry.getFriday().getHours() : 0.0);
		this.totalUnprodSaturday = totalUnprodSaturday + (null != occupationalEntry.getSaturday() ? occupationalEntry.getSaturday().getHours() : 0.0);
		this.totalUnprodSunday = totalUnprodSunday + (null != occupationalEntry.getSunday() ? occupationalEntry.getSunday().getHours() : 0.0);
	}

	private void addNonoccupationalHours() {
		this.totalUnprodMonday = totalUnprodMonday + (null != nonoccupationalEntry.getMonday() ? nonoccupationalEntry.getMonday().getHours() : 0.0);
		this.totalUnprodTuesday = totalUnprodTuesday + (null != nonoccupationalEntry.getTuesday() ? nonoccupationalEntry.getTuesday().getHours() : 0.0);
		this.totalUnprodWednesday = totalUnprodWednesday + (null != nonoccupationalEntry.getWednesday() ? nonoccupationalEntry.getWednesday().getHours() : 0.0);
		this.totalUnprodThursday = totalUnprodThursday + (null != nonoccupationalEntry.getThursday() ? nonoccupationalEntry.getThursday().getHours() : 0.0);
		this.totalUnprodFriday = totalUnprodFriday + (null != nonoccupationalEntry.getFriday() ? nonoccupationalEntry.getFriday().getHours() : 0.0);
		this.totalUnprodSaturday = totalUnprodSaturday + (null != nonoccupationalEntry.getSaturday() ? nonoccupationalEntry.getSaturday().getHours() : 0.0);
		this.totalUnprodSunday = totalUnprodSunday + (null != nonoccupationalEntry.getSunday() ? nonoccupationalEntry.getSunday().getHours() : 0.0);
	}

	private void clearTotalProdHours() {
		this.totalProdMonday = 0;
		this.totalProdTuesday = 0;
		this.totalProdWednesday = 0;
		this.totalProdThursday = 0;
		this.totalProdFriday = 0;
		this.totalProdSaturday = 0;
		this.totalProdSunday = 0;
		this.totalProdTotal = 0;
	}

	private void clearTotalUnprodHours() {
		this.totalUnprodMonday = 0;
		this.totalUnprodTuesday = 0;
		this.totalUnprodWednesday = 0;
		this.totalUnprodThursday = 0;
		this.totalUnprodFriday = 0;
		this.totalUnprodSaturday = 0;
		this.totalUnprodSunday = 0;
		this.totalUnprodTotal = 0;
	}

	private void createUnprodEntryList() {
		unprodWeekReportEntries = new ArrayList<WeekReportEntry>();
		unprodWeekReportEntries.add(depotManagementEntry);
		unprodWeekReportEntries.add(holidayEntry);
		unprodWeekReportEntries.add(compensationEntry);
		unprodWeekReportEntries.add(sicknessEntry);
		unprodWeekReportEntries.add(militaryEntry);
		unprodWeekReportEntries.add(occupationalEntry);
		unprodWeekReportEntries.add(nonoccupationalEntry);
	}

	private boolean reportEntryHasHoursFilled(WeekReportEntry entry) {
		return entry.getMonday().getHours() > 0 || entry.getTuesday().getHours() > 0 || entry.getWednesday().getHours() > 0 || entry.getThursday().getHours() > 0
				|| entry.getFriday().getHours() > 0 || entry.getSaturday().getHours() > 0 || entry.getSunday().getHours() > 0;
	}
}
